package cn.kduck.code.entity.service.impl;

import cn.kduck.code.entity.exception.ExistEntityCodeException;
import cn.kduck.code.entity.exception.ExistFieldCodeException;
import cn.kduck.code.entity.query.*;
import cn.kduck.code.entity.service.Entity;
import cn.kduck.code.entity.service.EntityField;
import cn.kduck.code.entity.service.EntityService;
import cn.kduck.core.dao.query.QuerySupport;
import cn.kduck.core.service.DefaultService;
import cn.kduck.core.service.ParamMap;
import cn.kduck.core.service.ValueMap;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.List;
import java.util.Map;


@Service
public class EntityServiceImpl extends DefaultService implements EntityService {

    @Override
    @Transactional
    public String addEntity(Entity entity) {
        String entityCode = entity.getEntityCode();
        Assert.hasText(entityCode,"实体编码不能为空");
        Assert.hasText(entity.getEntityName(),"实体名称不能为空");


        entityCode = entityCode.trim();
        if(existEntity(entityCode)){
            throw new ExistEntityCodeException(entityCode);
        }

        entity.setFieldCount(0);

        Serializable id = super.add(CODE_ENTITY, entity);

        return id.toString();
    }

    private boolean existEntity(String entityCode){
        Map<String, Object> paramMap = ParamMap.create("entityCode",entityCode).toMap();
        QuerySupport query = super.getQuery(EntityExistQuery.class, paramMap);
        return super.exist(query);
    }

    private void updateFieldCount(String entityId){
        Map<String, Object> paramMap = ParamMap.create("entityId", entityId).toMap();
        QuerySupport query = super.getQuery(CountEntityFieldQuery.class, paramMap);
        ValueMap valueMap = super.get(query);
        int fieldCount = valueMap.getValueAsInteger("fieldId");

        paramMap = ParamMap.create("entityId", entityId).set("fieldCount", fieldCount).toMap();
        super.update(CODE_ENTITY,paramMap);
    }

    @Override
    public String addEntityField(EntityField field) throws ExistFieldCodeException {
        Assert.hasText(field.getEntityId(),"实体ID不能为空");
        Assert.hasText(field.getFieldCode(),"实体字段编码不能为空");
        Assert.hasText(field.getFieldName(),"实体字段名称不能为空");

        Entity entity = getEntity(field.getEntityId());
        //检测添加的字段编码是否已经存在
        if(existField(field.getEntityId(),field.getFieldCode())){
            throw new ExistFieldCodeException(entity.getEntityCode(),field.getFieldCode());
        }

        int nextFieldOrderNum = getNextFieldOrderNum(field.getEntityId());
        field.setOrderNum(nextFieldOrderNum);

        Serializable id = super.add(CODE_ENTITY_FIELD, field);

        updateFieldCount(field.getEntityId());

        return id.toString();
    }

    private int getNextFieldOrderNum(String entityId){
        Map<String, Object> paramMap = ParamMap.create("entityId", entityId).toMap();
        QuerySupport query = getQuery(EntityFieldMaxOrderNumQuery.class, paramMap);
        ValueMap valueMap = super.get(query);
        Integer orderNum = valueMap.getValueAsInteger("orderNum");
        if(orderNum == null){
            return 1;
        }
        return orderNum + 1;
    }

    private boolean existField(String entityId, String fieldCode) {
        Map<String, Object> paramMap = ParamMap.create("entityId", entityId).set("fieldCode",fieldCode).toMap();
        QuerySupport query = super.getQuery(EntityFieldExistQuery.class, paramMap);
        return super.exist(query);
    }

    @Override
    public void updateEntity(Entity entity) {
        entity.removeValue("groupId","entityCode");
        super.update(CODE_ENTITY,entity);
    }

    @Override
    public void updateEntityField(EntityField field) {
        field.removeValue("fieldCode");
        super.update(CODE_ENTITY_FIELD,field);

    }

    @Override
    @Transactional
    public void deleteEntity(String[] entityIds) {
        super.delete(CODE_ENTITY_FIELD,"entityId",entityIds);
        super.delete(CODE_ENTITY,entityIds);

    }

    @Override
    public void deleteEntityField(String entityId,String[] fieldIds) {

        super.delete(CODE_ENTITY_FIELD,fieldIds);
        updateFieldCount(entityId);

    }

    @Override
    public Entity getEntity(String entityId) {
        return super.getForBean(CODE_ENTITY,entityId,Entity::new);
    }

    @Override
    public Entity getEntityByCode(String entityCode) {
        Map<String, Object> paramMap = ParamMap.create("entityCode", entityCode).toMap();
        QuerySupport query = super.getQuery(EntityQuery.class, paramMap);
        return super.getForBean(query,Entity::new);
    }

    @Override
    public EntityField getEntityField(String fieldId) {
        return super.getForBean(CODE_ENTITY_FIELD,fieldId,EntityField::new);
    }

    @Override
    public EntityField getEntityField(String entityId, String fieldCode) {
        Map<String, Object> paramMap = ParamMap.create("entityId", entityId).set("fieldCode", fieldCode).toMap();
        QuerySupport query = super.getQuery(EntityFieldQuery.class, paramMap);
        return super.getForBean(query,EntityField::new);
    }

    @Override
    public EntityField getEntityFieldByCode(String entityCode, String fieldCode) {
        Map<String, Object> paramMap = ParamMap.create("entityCode", entityCode).set("fieldCode", fieldCode).toMap();
        QuerySupport query = super.getQuery(EntityFieldByGroupIdQuery.class, paramMap);
        return super.getForBean(query,EntityField::new);
    }

    @Override
    public Entity getEntityByFieldId(String fieldId) {
        Map<String, Object> paramMap = ParamMap.create("fieldId", fieldId).toMap();
        QuerySupport query = super.getQuery(EntityByFieldIdQuery.class, paramMap);
        return super.getForBean(query,Entity::new);
    }

    @Override
    public List<EntityField> listEntityField(String entityId) {
        return listEntityField(entityId,null);
    }

    @Override
    public List<EntityField> listEntityField(String entityId,String fieldNameOrCode) {
        Map<String, Object> paramMap = ParamMap.create("entityId", entityId)
                .set("fieldNameOrCode",fieldNameOrCode).toMap();
        QuerySupport query = super.getQuery(EntityFieldQuery.class, paramMap);
        return super.listForBean(query, EntityField::new);
    }

    @Override
    public void sortEntityField(String[] sortedIds) {
        for (int i = 0; i < sortedIds.length; i++) {
            Map<String, Object> paramMap = ParamMap.create("fieldId", sortedIds[i])
                    .set("orderNum",i + 1).toMap();
            super.update(CODE_ENTITY_FIELD,paramMap);
        }
    }

    @Override
    public EntityField getPkField(String entityId) {
        Map<String, Object> paramMap = ParamMap.create("entityId", entityId).set("isKey",1).toMap();
        QuerySupport query = super.getQuery(EntityFieldQuery.class, paramMap);
        EntityField pkEntityField = super.getForBean(query, EntityField::new);
        if(pkEntityField == null){
            throw new RuntimeException("实体中没有找到主键字段，请检查数据。entityId="+entityId);
        }
        return pkEntityField;
    }

    @Override
    public List<Entity> listEntity() {
        QuerySupport query = super.getQuery(EntityQuery.class, ParamMap.create().toMap());
        return super.listForBean(query, Entity::new);
    }

}
